Quat = {}

function Quat.New(w, x, y, z)
    return {w = w, x = x, y = y, z = z}
end

function Quat.Mul(q1, q2)
    return Quat.New(
        q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,
        q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
        q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z,
        q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x
    )
end

function Quat.Transfrom(q, v){
    local i = {x = q.x, y = q.y, z = q.z}
    local v_cross_i = {
        x = v.y * i.z - v.z * i.y,
        y = v.z * i.x - v.x * i.z,
        z = v.x * i.y - v.y * i.x
    }
    local v_cross_i_times_i = {
        x = i.y * v_cross_i.z - i.z * v_cross_i.y,
        y = i.z * v_cross_i.x - i.x * v_cross_i.z,
        z = i.x * v_cross_i.y - i.y * v_cross_i.x
    }
    local result = {
        x = v.x + 2 * (q.w * i.x + v_cross_i.x + v_cross_i_times_i.x),
        y = v.y + 2 * (q.w * i.y + v_cross_i.y + v_cross_i_times_i.y),
        z = v.z + 2 * (q.w * i.z + v_cross_i.z + v_cross_i_times_i.z)
    }
    return result
}

return Quat